using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Configuration;
using System.Xml;
using System.Xml.XPath;


namespace Jasongozy.Alaton {

	public class AppConfig {

		public static Dictionary<string,string> Settings = new Dictionary<string,string>();

		static AppConfig() {

			initializeSettings();
			
		}
	
		#region implement Alaton.AppConfig.Import and Alaton.AppConfig.Import.MergePath

        
		private static void initializeSettings(
		) {
			//
			// parse any external override settings...
			//
			Dictionary<string,string> overrideSettings = parseOverrideSettings();

			//
			// import extension settings
			//
			importSettings(overrideSettings);

			//
			// merge in the standard .net appSettings definitions -- (2nd highest priority)
			//
            NameValueCollection nativeSettings = ConfigurationManager.AppSettings;
			foreach(string key in nativeSettings.Keys) {
				AppConfig.Settings[key] = nativeSettings[key];
			}
			
			//
			// merge in the external override settings -- (highest priority)
			//
			foreach(string key in overrideSettings.Keys) {
				AppConfig.Settings[key] = overrideSettings[key];
			}
		
		}

		private static string resolveOverrideSetting(
			Dictionary<string,string> overrideSettings,
			string key
		) {

			if (overrideSettings.ContainsKey(key) && overrideSettings[key] != null)
				return overrideSettings[key];
			else
				return ConfigurationManager.AppSettings[key];
		}

        public static void LoadRemoteSetting()
        {
            importSettings(AppConfig.Settings, true);
        }

        private static void importSettings(Dictionary<string,string> overrideSettings, bool isRemoteSetting)
        {
            //
            // extract the path of import merging
            //
            string importMergePath = resolveOverrideSetting(overrideSettings, "Alaton.AppConfig.Import.MergePath");

            //
            // construct the stack of import merge paths...
            //
            Stack importPathStack;
            if (importMergePath != null)
            {
                string[] importMergeNames = importMergePath.Split('\\');
                Array.Reverse(importMergeNames);
                importPathStack = new Stack(importMergeNames.Length);
                for (int l = 0; l < importMergeNames.Length; l++) importPathStack.Push(importMergeNames[l].Trim());
            }
            else
            {
                importPathStack = new Stack(0);
            }

            //
            // determine the base app path to import settings from
            //
            string appConfigBaseDirectory = null;
            if (!isRemoteSetting)
            {
                appConfigBaseDirectory = resolveOverrideSetting(overrideSettings, "Alaton.AppConfig.Import.AppPath");
            }
            else
            {
                appConfigBaseDirectory = resolveOverrideSetting(overrideSettings, "Alaton.AppConfig.Import.RemoteAppPath");
            }
            if ((appConfigBaseDirectory == null) || (appConfigBaseDirectory == "."))
                appConfigBaseDirectory = System.AppDomain.CurrentDomain.BaseDirectory;

            //
            // determine the _appConfig directory relative to the current
            // application domain's startup/instance path...
            //
            string appConfigDirectory = System.IO.Path.Combine(
                appConfigBaseDirectory,
                "_appConfig"
            );


            string[] importNames = parseImportNames(overrideSettings, appConfigDirectory, importPathStack.Clone() as Stack);
            //
            // recursive switch-folder setting parse...
            //
            mergeImportFolderSettings(appConfigDirectory, importNames, importPathStack.Clone() as Stack);
        }


		private static void importSettings(	
			Dictionary<string,string> overrideSettings
        )
        {
            importSettings(overrideSettings, false);
		}

		private static void addImportNames(
			string importList,
			Hashtable nameHistory,
			ArrayList nameList
		) {
			if (importList != null) {
				//
				// parse the import name list
				//
				string[] importNames = importList.Split(';');
				for(int l=0; l < importNames.Length; l++) {
					string importName = importNames[l].Trim();
					if ((importName == "") || (nameHistory[importName.ToUpper()] != null)) continue;
					
					nameHistory[importName.ToUpper()] = "";
					nameList.Add(importName);
				}			
			}		
		}

		private static string[] parseImportNames(
			Dictionary<string,string> overrideSettings,
			string directoryPath,
			Stack importPathStack
		) {
			
			Hashtable nameHistory = new Hashtable();
			ArrayList nameList = new ArrayList();
			
			//
			// start with the basics
			//		
			string importList = resolveOverrideSetting(overrideSettings, "Alaton.AppConfig.Import");
			addImportNames(importList, nameHistory, nameList);

			
			string mergeDirectoryPath = directoryPath;		
			importPathStack.Push(""); // to scan the base directory as well
			
			while (importPathStack.Count > 0) {
				string mergePath = importPathStack.Pop() as string;
				if (mergePath != null) {
				
					
					mergeDirectoryPath = System.IO.Path.Combine(
						mergeDirectoryPath,
						mergePath
					);
				
					string mergeNameFilePath = System.IO.Path.Combine(
						mergeDirectoryPath,
						"Alaton.AppConfig.Import.list"
					);
					
					if (System.IO.File.Exists(mergeNameFilePath)) {
						
						using (StreamReader importReader = new StreamReader(File.OpenRead(mergeNameFilePath))) {
							importList = importReader.ReadToEnd();
							
							addImportNames(importList, nameHistory, nameList);
						}
					}
					
					
				}
			}
			
			return nameList.ToArray(typeof(string)) as string[];

			
						
		}
		


		private static Dictionary<string,string> parseOverrideSettings(
		) {
			string deploymentOverrideFilename = Path.Combine(
				System.AppDomain.CurrentDomain.BaseDirectory,
				"Alaton.AppConfig.Override.config"
			);
			Dictionary<string,string> overrideSettings = new Dictionary<string,string>();
			mergeImportSettings(deploymentOverrideFilename, overrideSettings);
			return overrideSettings;		
		}



		private static void mergeImportFolderSettings(
			string directoryPath,
			string[] importNames,
			Stack importMergePathStack
		) {
			
			//
			// skip if folder doesn't exist...
			//
			if (System.IO.Directory.Exists(directoryPath) == false) return;
			
			//
			// parse each import setting file...
			//
			foreach(string importName in importNames) {
			
				string importSettingsPath = System.IO.Path.Combine(directoryPath,importName + ".config");
				
				mergeImportSettings(
					importSettingsPath,
					AppConfig.Settings
				);
				
				string importSQLPath = System.IO.Path.Combine(directoryPath,importName + ".sql.config");
				sqlSettings.importSettings(importSQLPath);
			}
		

			//
			// step to the next merge folder path, if any...
			//
			if (importMergePathStack.Count >0) {
				string mergePath = importMergePathStack.Pop() as string;
				if (mergePath != null) {
				
					
					string mergeDirectoryPath = System.IO.Path.Combine(
						directoryPath,
						mergePath
					);
				
					mergeImportFolderSettings(
						mergeDirectoryPath,
						importNames,
						importMergePathStack
					);
					
				}
			}
		}
	
		/// <summary>
		/// Actually parses the config keys out of a particular file
		/// </summary>
		/// <param name="importSettingsPath"></param>
		/// <param name="settings"></param>
		private static void mergeImportSettings(
			string importSettingsPath,
			Dictionary<string,string> settings
		) {
				if (System.IO.File.Exists(importSettingsPath)) {
					#region parse xml Settings, merge
					XPathDocument settingsDom = new XPathDocument(importSettingsPath);
					XPathNodeIterator Settings = settingsDom.CreateNavigator().Select("appSettings/add");
					
					while(Settings.MoveNext()) {
						string key		= Settings.Current.GetAttribute("key", "");
						string value	= Settings.Current.GetAttribute("value", "");
						
						settings[key] =value;
						
					}
					#endregion
				}		
		}
		
		#region SQL Settings
		
		
		
		#region SqlDatabaseSettings
		public interface ISqlDatabaseSettings {
		
			string Alias { get; }
			string Name { get; }
			
			ISqlServerSettings Server { get; }

			
		}
		private class SqlDatabaseSettings : ISqlDatabaseSettings {
			private string server; // server alias;
			private string alias;
			private string name;
			public string Alias { get { return this.alias; }}
			public string Name { get { return this.name; }}
			
			public ISqlServerSettings Server { get {
				return sqlSettings[this.server];
			}}

			
			internal SqlDatabaseSettings(string server, string alias) {
				this.server = server;
				this.alias = alias;
			}
			
			internal void importSettings(
				XPathNavigator nav
			) {
				this.name = nav.GetAttribute("name",""); if (this.name == "") this.name = this.alias;
			}
		}
		#endregion
		
		#region SqlConnectionSettings
		public interface ISqlConnectionSettings {
			string Alias { get; }
			string ConnectionString { get; }
		}
		private class SqlConnectionSettings : ISqlConnectionSettings {
			private string alias;
			private string connectionString = null;
			
			public string Alias { get { return this.alias; }}
			public string ConnectionString { get { return this.connectionString; }} 
			internal SqlConnectionSettings(string alias) {
				this.alias = alias;
			}
			
			internal void importSettings(
				XPathNavigator nav
			) {
			
				string connectionString = nav.GetAttribute("connectionString","");
				if (connectionString != null)
					this.connectionString = connectionString;
			}			
			
			
		}
		#endregion
		
		#region SqlServerSettings
		
		public interface ISqlServerSettings {
			string Alias { get; }
			string Name { get; } 
			
			ISqlConnectionSettings GetConnectionType(
				string alias
			);
			
			ISqlDatabaseSettings GetDatabase(
				string alias
			);
			
			ISqlDatabaseSettings this[string alias] { get; } 
		}
		
		private class SqlServerSettings : ISqlServerSettings {
			private string alias;
			private string name;
			private IDictionary databases = new Hashtable();		
			private IDictionary connectionTypes = new Hashtable();
			
			internal SqlServerSettings(
				string alias
			) {
				this.alias = alias;
			}
			
			public string Alias { get { return this.alias; }}
			public string Name { get { return this.name; }}
			/// <summary>
			/// access ConnectionType settings by connection type alias
			/// </summary>
			/// <param alias="alias"></param>
			/// <returns></returns>
			public ISqlConnectionSettings GetConnectionType(
				string alias
			) {
				return this.connectionTypes[alias] as SqlConnectionSettings;
			}
			
			/// <summary>
			/// access Database settings by database alias
			/// </summary>
			/// <param alias="alias"></param>
			/// <returns></returns>
			public ISqlDatabaseSettings GetDatabase(
				string alias
			) {
				return this.databases[alias] as SqlDatabaseSettings;
			}
			
			/// <summary>
			/// access Database settings by database alias
			/// </summary>
			public ISqlDatabaseSettings this[string alias] {
				get {
					return this.GetDatabase(alias);
				}
			}
			
			internal void importSettings(
				XPathNavigator nav
			) {
				this.name = nav.GetAttribute("name",""); if (this.name == "") this.name = this.alias;
			
				XPathNodeIterator connectionTypeNodes = nav.Select("connectionType");
				
				#region parse connection types
				while (connectionTypeNodes.MoveNext()) {
					
					string connectionTypeName = connectionTypeNodes.Current.GetAttribute("alias","");
					
					SqlConnectionSettings connectionType = this.connectionTypes[connectionTypeName] as SqlConnectionSettings;
					if (connectionType == null) {
						connectionType = new SqlConnectionSettings(connectionTypeName);
						this.connectionTypes[connectionTypeName] = connectionType;
					}
					
					connectionType.importSettings(connectionTypeNodes.Current);
					
					
				}
				#endregion
					
				#region parse databases
				XPathNodeIterator databaseNodes = nav.Select("database");
				
				while (databaseNodes.MoveNext()) {
					
					string databaseName = databaseNodes.Current.GetAttribute("alias","");
					
					SqlDatabaseSettings database = this.databases[databaseName] as SqlDatabaseSettings;
					if (database == null) {
						database = new SqlDatabaseSettings(this.name,databaseName);
						this.databases[databaseName] = database;
					}
					
					database.importSettings(databaseNodes.Current);
					
					
				}
				#endregion
			
			}
			
		}
		#endregion
		
		#region SqlSettings
		public interface ISqlSettings {
			ISqlServerSettings this[string alias] { get; }
			
			ISqlServerSettings GetServerOfDatabase(string databaseName);
			ISqlDatabaseSettings GetDatabase(string databaseName);
			
			string GetConnectionString(
				string database,
				string connectionType
			);
		
		}
		
		private class SqlSettings : ISqlSettings {
			
			private IDictionary servers = new Hashtable();
			
			private IDictionary serversByDatabase = new Hashtable();
			
			public ISqlServerSettings this[string alias] {
				get {
					return this.servers[alias] as SqlServerSettings;
				}
			}
			
			public ISqlDatabaseSettings GetDatabase(
				string databaseName
			) {
				ISqlServerSettings server = this.GetServerOfDatabase(databaseName);
				return (server != null) ? server[databaseName] : null;
			}
			
			public ISqlServerSettings GetServerOfDatabase(
				string databaseName
			) {
				ISqlServerSettings server = this.serversByDatabase[databaseName] as ISqlServerSettings;
				if (server != null) return server;
				
				foreach(ISqlServerSettings findServer in this.servers.Values) {
					if (findServer.GetDatabase(databaseName) != null) {
						this.serversByDatabase[databaseName] = findServer;
						return findServer;
					}
				}
				return null;
			}
			
			
			/// <summary>
			/// Returns a connection string by looking one up in .sql.config files
			/// based on the parameter provided
			/// </summary>
			/// <param name="databaseExpression">can be "Database" or "Server:Database" format</param>
			/// <param name="connectionType"></param>
			/// <returns></returns>
			public string GetConnectionString(
				string databaseExpression,
				string connectionType
			) {

				AppConfig.ISqlServerSettings sqlServerSettings;
				string database;
			
				int delimIndex = databaseExpression.IndexOf(':');							
				if (delimIndex == -1) {
					database = databaseExpression;
					sqlServerSettings = AppConfig.Sql.GetServerOfDatabase(database);
				} else {
					database = databaseExpression.Substring(delimIndex+1);
					string server = databaseExpression.Substring(0, delimIndex);
					sqlServerSettings = AppConfig.Sql[server];
				}

				AppConfig.ISqlConnectionSettings sqlConnectionSettings = (sqlServerSettings != null) ? sqlServerSettings.GetConnectionType(connectionType) : null;
				AppConfig.ISqlDatabaseSettings sqlDatabaseSettings = (sqlServerSettings != null) ? sqlServerSettings[database] : null;				
				
				if (
					(sqlServerSettings != null)
					&&
					(sqlDatabaseSettings != null)
					&&
					(sqlConnectionSettings != null)
				) {
				
					
					return (String.Format(
						"{0};Database={1}",
						sqlConnectionSettings.ConnectionString,
						sqlDatabaseSettings.Name
					));
					
				} else {
					return null;
				}
			
			}
			
			internal void importSettings(
				string importSettingsPath
			) {
				#region parse file
				if (System.IO.File.Exists(importSettingsPath)) {
					#region parse xml Settings, merge
					XPathDocument settingsDom = new XPathDocument(importSettingsPath);
					XPathNodeIterator Settings = settingsDom.CreateNavigator().Select("sqlConfig/server");
					
					while(Settings.MoveNext()) {
						string serverName		= Settings.Current.GetAttribute("alias", "");
						
						
						SqlServerSettings server = this.servers[serverName] as SqlServerSettings;
						if (server == null) {
							server = new SqlServerSettings(serverName);
							this.servers[serverName] = server;
						}
						
						server.importSettings(
							Settings.Current
						);
						
						
					}
					#endregion
				}				
				#endregion
			}
		}
		
		#endregion
		
		private static SqlSettings sqlSettings = new SqlSettings();
		
		#endregion
		
		#endregion
	
		
		/// <summary>
		/// Provides access to statically parsed SQL Server/Database/Connection configuration information.
		/// </summary>
		public static ISqlSettings Sql { get { return sqlSettings; }} 
	
		public static string GetSetting(string key) {
            if (!AppConfig.Settings.ContainsKey(key)) return null;
			return AppConfig.Settings[key];
		}	

	
		#region Exceptions

		public class ConfigSettingMissingException : ApplicationException {
			public ConfigSettingMissingException(string setting) : base("Required configuration setting " + setting + " not present") {
			}
		}

		public class DirectoryDoesNotExistException : DirectoryNotFoundException {
			public DirectoryDoesNotExistException(DirectoryInfo dir) : this(dir.FullName) {
			}

			public DirectoryDoesNotExistException(string dirName) : base("Directory " + dirName + " does not exist") {
			}
		}

		public class FileDoesNotExistException : FileNotFoundException {
			public FileDoesNotExistException(FileInfo file) : this(file.FullName) {
			}

			public FileDoesNotExistException(string fileName) : base("File " + fileName + " does not exist") {
			}
		}

		#endregion

		/// <summary>
		/// Returns an array of semicolon-separated directories specified
		/// by the configuration setting.  The directories may not exist.
		/// </summary>
		public static DirectoryInfo[] GetDirectoriesFromSetting(string key) {

			string[] dirsStrs = AppConfig.GetRequiredSetting(key).Split(';');

			ArrayList dirs = new ArrayList();
			foreach (string dirStr in dirsStrs) {
				DirectoryInfo dir = new DirectoryInfo(dirStr);
				dirs.Add(dir);
			}
			return (DirectoryInfo[]) dirs.ToArray(typeof(DirectoryInfo));
		}

		/// <summary>
		/// Get a directory from a configuration setting.  The directory
		/// may not exist, but the setting MUST be set.
		/// </summary>
		public static DirectoryInfo GetDirectoryFromSetting(string key) {

			return new DirectoryInfo(GetRequiredSetting(key));
		}

		/// <summary>
		/// Returns an array of semicolon-separated directories specified
		/// by the configuration setting.  Each directory must already
		/// exist.
		/// </summary>
		public static DirectoryInfo[] GetExistingDirectoriesFromSetting(string key) {

			DirectoryInfo[] dirs = GetDirectoriesFromSetting(key);
			foreach (DirectoryInfo dir in dirs) {
				if (!dir.Exists) {
					throw new DirectoryDoesNotExistException(dir);
				}
			}
			return dirs;
		}

		/// <summary>
		/// Get a directory from a configuration setting.  The directory
		/// must already exist.
		/// </summary>
		public static DirectoryInfo GetExistingDirectoryFromSetting(string key) {

			DirectoryInfo dir = GetDirectoryFromSetting(key);
			if(!dir.Exists) {
				throw new DirectoryDoesNotExistException(dir);
			}
			return dir;
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a semi-colon
		/// separated string array.  Returns null if the setting is
		/// not set.
		/// </summary>
		public static string[] GetOptionalSettingAsArray(string key) {

			return GetOptionalSettingAsArray(key, ';');
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a string
		/// array separated by the provided separator.  Returns null
		/// if the setting is not set.
		/// </summary>
		public static string[] GetOptionalSettingAsArray(string key, char separator) {

			return GetOptionalSettingAsArray(key, separator, null);
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a string
		/// array separated by the provided separator.  Returns defaultVal
		/// if the setting is not set.
		/// </summary>
		public static string[] GetOptionalSettingAsArray(string key, char separator, string[] defaultVal) {

			string val = GetSetting(key);
			if (val == null) {
				return defaultVal;
			}

			return val.Split(separator);
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a boolean.
		/// Returns defaultVal if the setting is not set.
		/// </summary>
		public static string GetOptionalSetting(string key) {
			return GetOptionalSetting(key,null);
		}
		
		/// <summary>
		/// Get a setting from app.config or Web.config as a boolean.
		/// Returns defaultVal if the setting is not set.
		/// </summary>
		public static string GetOptionalSetting(string key, string defaultVal) {
			string val = GetSetting(key);
			if (val == null)
				return defaultVal;
			return val;
		}

		public static object GetOptionalSettingAsEnum(
			string key,
			System.Type enumType,
			System.Enum defaultVal
		) {
			string val = GetSetting(key);
			if (val == null) return defaultVal;
			
			return System.Enum.Parse(enumType, val, true);
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a boolean.
		/// Returns defaultVal if the setting is not set.
		/// </summary>
		public static bool GetOptionalSettingAsBool(string key, bool defaultVal) {
			string val = GetSetting(key);
			if (val == null)
				return defaultVal;
			return bool.Parse(val);
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a double.
		/// Returns a null value if the setting is not set.
		/// </summary>
        public static double? GetOptionalSettingAsDouble(string key) {
			string val = GetSetting(key);
            double? res = null;
            if (val != null)
                res = double.Parse(val);
            return res;
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a file.
		/// Returns null if the setting is not set.  If the setting is set,
		/// the file must exist.
		/// </summary>
		public static FileInfo GetOptionalSettingAsExistingFile(string key) {

			FileInfo fi = GetOptionalSettingAsFile(key);
			if (fi == null) {
				return null;
			}
			if(!fi.Exists) {
				throw new FileDoesNotExistException(fi);
			}

			return fi;
		}

		public static FileInfo GetOptionalSettingAsFile(string key) {
			
			string val = GetSetting(key);
			if (val == null) {
				return null;
			}

			return new FileInfo(val);
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as an integer.
		/// Returns the null value if the setting is not set.
		/// </summary>
		public static int? GetOptionalSettingAsInt(string key) {

			string val = GetSetting(key);
            int? res = null;
            if (val != null)
                res = int.Parse(val);
            return res;
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as an integer.
		/// Returns defaultVal if the setting is not set.
		/// </summary>
		public static int GetOptionalSettingAsInt(string key, int defaultVal) {

			string val = GetSetting(key);
			if (val == null) {
				return defaultVal;
			}

			return int.Parse(val);
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as an integer array.
		/// Returns null if the setting is not set.
		/// </summary>
		public static int[] GetOptionalSettingAsIntArray(string key) {

			string[] intStrs = GetOptionalSettingAsArray(key);
			if (intStrs == null) {
				return null;
			}

			ArrayList intList = new ArrayList();
			foreach (string intStr in intStrs) {
				int i = int.Parse(intStr);
				intList.Add(i);
			}

			return (int[]) intList.ToArray(typeof(int));
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as an unsigned
		/// integer.  Returns the null value if the setting is not set.
		/// </summary>
		public static UInt32? GetOptionalSettingAsUInt(string key) {

			string val = GetSetting(key);
            UInt32? res = null;
            if (val != null)
                res = UInt32.Parse(val);
            return res;
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a semi-colon
		/// separated string array.  Throws an exception if the setting is
		/// not set.
		/// </summary>
		public static string[] GetRequiredSettingAsArray(string key) {

			return GetRequiredSettingAsArray(key, ';');
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as a string
		/// array separated by the provided separator.  Throws an exception
		/// if the setting is not set.
		/// </summary>
		public static string[] GetRequiredSettingAsArray(string key, char separator) {

			string[] val = GetOptionalSettingAsArray(key, separator);
			if (val == null) {
				throw new ConfigSettingMissingException(key);
			}

			return val;
		}

		/// <summary>
		/// Get a file from a configuration setting.  The file must already
		/// exist.
		/// </summary>
		public static FileInfo GetRequiredSettingAsExistingFile(string key) {

			FileInfo fi = GetRequiredSettingAsFile(key);
			if (!fi.Exists) {
				throw new FileDoesNotExistException(fi);
			}
			return fi;
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as an integer.
		/// Throws an exception if the setting is not set.  The file is
		/// not required to exist.
		/// </summary>
		public static FileInfo GetRequiredSettingAsFile(string key) {
			
			return new FileInfo(GetRequiredSetting(key));
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as an integer.
		/// Throws an exception if the setting is not set or is not
		/// an integer.
		/// </summary>
		public static int GetRequiredSettingAsInt(string key) {

			return int.Parse(GetRequiredSetting(key));
		}

		/// <summary>
		/// Get a setting from app.config or Web.config as an integer array.
		/// Throws an exception if the setting is not set or is not
		/// an integer array.
		/// </summary>
		public static int[] GetRequiredSettingAsIntArray(string key) {

			int[] val = GetOptionalSettingAsIntArray(key);
			if (val == null) {
				throw new ConfigSettingMissingException(key);
			}
			
			return val;
		}

		/// <summary>
		/// Get a setting from app.config or Web.config.  Throws an exception
		/// if the setting is not set (which is better than a null pointer
		/// exception later)
		/// </summary>
		public static string GetRequiredSetting(string key) {

			string val = GetSetting(key);
			if (val == null) {
				throw new ConfigSettingMissingException(key);
			}

			return val;
		}
	
        public static void ReLoad()
        {
            initializeSettings();
        }
    }
}
